﻿using System;
using System.Collections.Generic;
using IrrlichtLime;
using IrrlichtLime.Core;
using Timed;
using IrrlichtLime.Scene;
using IrrlichtLime.Video;
using IrrKlang;
using LuaInterface;
using System.Reflection;
using Iso.Common;

namespace Iso.Core
{
    public static class LuaHook
    {
        public static void Register()
        {
            // General
            // ---------------------------------------------------------
            Engine.lua.RegisterFunction("Call", null, typeof(LuaHook).GetMethod("Call"));
            Engine.lua.RegisterFunction("Lerp", null, typeof(LuaHook).GetMethod("Lerp"));
            Engine.lua.RegisterFunction("Clamp", null, typeof(LuaHook).GetMethod("Clamp"));
            Engine.lua.RegisterFunction("Vector2i", null, typeof(LuaHook).GetMethod("Vector2i"));
            Engine.lua.RegisterFunction("Vector2", null, typeof(LuaHook).GetMethod("Vector2"));
            Engine.lua.RegisterFunction("Vector3", null, typeof(LuaHook).GetMethod("Vector3"));
            Engine.lua.RegisterFunction("Color", null, typeof(LuaHook).GetMethod("Color"));
            Engine.lua.RegisterFunction("Rect", null, typeof(LuaHook).GetMethod("Rect"));
            Engine.lua.RegisterFunction("PointInside", null, typeof(LuaHook).GetMethod("PointInside"));
            Engine.lua.RegisterFunction("StringArray", null, typeof(LuaHook).GetMethod("StringArray"));
            Engine.lua.RegisterFunction("KeyCode", null, typeof(LuaHook).GetMethod("KeyCode"));
            Engine.lua.RegisterFunction("MouseEvent", null, typeof(LuaHook).GetMethod("MouseEvent"));

            // Engine
            // ---------------------------------------------------------
            Engine.lua.RegisterFunction("BaseData", null, typeof(LuaHook).GetMethod("BaseData"));
            //Engine.lua.RegisterFunction("LoadPlugin", null, typeof(LuaHook).GetMethod("LoadPlugin"));
            Engine.lua.RegisterFunction("ClearTextures", null, typeof(LuaHook).GetMethod("ClearTextures"));
            Engine.lua.RegisterFunction("GetGlobalVariable", null, typeof(LuaHook).GetMethod("GetGlobalVariable"));
            Engine.lua.RegisterFunction("SetGlobalVariable", null, typeof(LuaHook).GetMethod("SetGlobalVariable"));
            Engine.lua.RegisterFunction("SetTitle", null, typeof(LuaHook).GetMethod("SetTitle"));

            // Files
            Engine.lua.RegisterFunction("ReadFile", null, typeof(LuaHook).GetMethod("ReadFile"));
            Engine.lua.RegisterFunction("WriteFile", null, typeof(LuaHook).GetMethod("WriteFile"));

            // Keyboard
            Engine.lua.RegisterFunction("KeyboardReset", null, typeof(LuaHook).GetMethod("KeyboardReset"));
            Engine.lua.RegisterFunction("KeyboardDown", null, typeof(LuaHook).GetMethod("KeyboardDown"));

            // Load Scene
            Engine.lua.RegisterFunction("LoadField", null, typeof(LuaHook).GetMethod("LoadField"));
            Engine.lua.RegisterFunction("LoadFieldPOS", null, typeof(LuaHook).GetMethod("LoadFieldPOS"));
            Engine.lua.RegisterFunction("LoadScene", null, typeof(LuaHook).GetMethod("LoadScene"));
            Engine.lua.RegisterFunction("EndGame", null, typeof(LuaHook).GetMethod("EndGame"));

            // Timeline
            Engine.lua.RegisterFunction("GetCurrentTime", null, typeof(LuaHook).GetMethod("GetCurrentTime"));
            Engine.lua.RegisterFunction("AddTimeTrigger", null, typeof(LuaHook).GetMethod("AddTimeTrigger"));
            Engine.lua.RegisterFunction("AddTimeTriggerLerp", null, typeof(LuaHook).GetMethod("AddTimeTriggerLerp"));

            // Sound
            Engine.lua.RegisterFunction("PlaySound", null, typeof(LuaHook).GetMethod("PlaySound"));
            Engine.lua.RegisterFunction("FadeInSound", null, typeof(LuaHook).GetMethod("FadeInSound"));
            Engine.lua.RegisterFunction("FadeOutSound", null, typeof(LuaHook).GetMethod("FadeOutSound"));
            Engine.lua.RegisterFunction("StopSound", null, typeof(LuaHook).GetMethod("StopSound"));
            Engine.lua.RegisterFunction("StopAllSound", null, typeof(LuaHook).GetMethod("StopAllSound"));
            Engine.lua.RegisterFunction("GetSound", null, typeof(LuaHook).GetMethod("GetSound"));
            Engine.lua.RegisterFunction("MainVolume", null, typeof(LuaHook).GetMethod("MainVolume"));

            // Field
            // ---------------------------------------------------------
            Engine.lua.RegisterFunction("AddCustomPlugin", null, typeof(LuaHook).GetMethod("AddCustomPlugin"));
            Engine.lua.RegisterFunction("GetCustomPlugin", null, typeof(LuaHook).GetMethod("GetCustomPlugin"));
            Engine.lua.RegisterFunction("RemoveCustomPlugin", null, typeof(LuaHook).GetMethod("RemoveCustomPlugin"));
            Engine.lua.RegisterFunction("FadeIn", null, typeof(LuaHook).GetMethod("FadeIn"));
            Engine.lua.RegisterFunction("FadeOut", null, typeof(LuaHook).GetMethod("FadeOut"));
            Engine.lua.RegisterFunction("BasePlane", null, typeof(LuaHook).GetMethod("BasePlane"));
            Engine.lua.RegisterFunction("SpriteRotation", null, typeof(LuaHook).GetMethod("SpriteRotation"));
            Engine.lua.RegisterFunction("CamLimits", null, typeof(LuaHook).GetMethod("CamLimits"));
            Engine.lua.RegisterFunction("CamPos", null, typeof(LuaHook).GetMethod("CamPos"));
            Engine.lua.RegisterFunction("CamIso", null, typeof(LuaHook).GetMethod("CamIso"));

            // Objects
            Engine.lua.RegisterFunction("AddObject", null, typeof(LuaHook).GetMethod("AddObject"));
            Engine.lua.RegisterFunction("AddObjectCameraFacing", null, typeof(LuaHook).GetMethod("AddObjectCameraFacing"));
            Engine.lua.RegisterFunction("GetObject", null, typeof(LuaHook).GetMethod("GetObject"));
            Engine.lua.RegisterFunction("AnimateObject", null, typeof(LuaHook).GetMethod("AnimateObject"));
            Engine.lua.RegisterFunction("RemoveObject", null, typeof(LuaHook).GetMethod("RemoveObject"));
            Engine.lua.RegisterFunction("ObjectTransparent", null, typeof(LuaHook).GetMethod("ObjectTransparent"));

            // Player
            Engine.lua.RegisterFunction("AddPlayer", null, typeof(LuaHook).GetMethod("AddPlayer"));
            Engine.lua.RegisterFunction("AddPlayerCameraFacing", null, typeof(LuaHook).GetMethod("AddPlayerCameraFacing"));
            Engine.lua.RegisterFunction("GetPlayer", null, typeof(LuaHook).GetMethod("GetPlayer"));
            Engine.lua.RegisterFunction("RemovePlayer", null, typeof(LuaHook).GetMethod("RemovePlayer"));
            Engine.lua.RegisterFunction("SetPlayer", null, typeof(LuaHook).GetMethod("SetPlayer"));
            Engine.lua.RegisterFunction("PlayerControl", null, typeof(LuaHook).GetMethod("PlayerControl"));
            Engine.lua.RegisterFunction("AnimatePlayer", null, typeof(LuaHook).GetMethod("AnimatePlayer"));
            Engine.lua.RegisterFunction("MovePlayer", null, typeof(LuaHook).GetMethod("MovePlayer"));
            Engine.lua.RegisterFunction("TimedAnimatePlayer", null, typeof(LuaHook).GetMethod("TimedAnimatePlayer"));
            Engine.lua.RegisterFunction("LerpMovePlayer", null, typeof(LuaHook).GetMethod("LerpMovePlayer"));
            
            // NPCs
            Engine.lua.RegisterFunction("AddNPC", null, typeof(LuaHook).GetMethod("AddNPC"));
            Engine.lua.RegisterFunction("AddNPCCameraFacing", null, typeof(LuaHook).GetMethod("AddNPCCameraFacing"));
            Engine.lua.RegisterFunction("GetNPC", null, typeof(LuaHook).GetMethod("GetNPC"));
            Engine.lua.RegisterFunction("RemoveNPC", null, typeof(LuaHook).GetMethod("RemoveNPC"));
            Engine.lua.RegisterFunction("AnimateNPC", null, typeof(LuaHook).GetMethod("AnimateNPC"));
            Engine.lua.RegisterFunction("MoveNPC", null, typeof(LuaHook).GetMethod("MoveNPC"));
            Engine.lua.RegisterFunction("TimedAnimateNPC", null, typeof(LuaHook).GetMethod("TimedAnimateNPC"));
            Engine.lua.RegisterFunction("LerpMoveNPC", null, typeof(LuaHook).GetMethod("LerpMoveNPC"));

            // Triggers
            Engine.lua.RegisterFunction("AddTrigger", null, typeof(LuaHook).GetMethod("AddTrigger"));
            Engine.lua.RegisterFunction("RemoveTrigger", null, typeof(LuaHook).GetMethod("RemoveTrigger"));

            // UI
            Engine.lua.RegisterFunction("AddMenu", null, typeof(LuaHook).GetMethod("AddMenu"));
            Engine.lua.RegisterFunction("GetMenu", null, typeof(LuaHook).GetMethod("GetMenu"));
            Engine.lua.RegisterFunction("RemoveMenu", null, typeof(LuaHook).GetMethod("RemoveMenu"));
            Engine.lua.RegisterFunction("AddText", null, typeof(LuaHook).GetMethod("AddText"));
            Engine.lua.RegisterFunction("GetText", null, typeof(LuaHook).GetMethod("GetText"));
            Engine.lua.RegisterFunction("RemoveText", null, typeof(LuaHook).GetMethod("RemoveText"));
            Engine.lua.RegisterFunction("AddRect", null, typeof(LuaHook).GetMethod("AddRect"));
            Engine.lua.RegisterFunction("RemoveRect", null, typeof(LuaHook).GetMethod("RemoveRect"));
            Engine.lua.RegisterFunction("AddSprite", null, typeof(LuaHook).GetMethod("AddSprite"));
            Engine.lua.RegisterFunction("GetSprite", null, typeof(LuaHook).GetMethod("GetSprite"));
            Engine.lua.RegisterFunction("AnimateSprite", null, typeof(LuaHook).GetMethod("AnimateSprite"));
            Engine.lua.RegisterFunction("RemoveSprite", null, typeof(LuaHook).GetMethod("RemoveSprite"));
            Engine.lua.RegisterFunction("SetBackground", null, typeof(LuaHook).GetMethod("SetBackground"));
            Engine.lua.RegisterFunction("SetForeground", null, typeof(LuaHook).GetMethod("SetForeground"));
            Engine.lua.RegisterFunction("Capture", null, typeof(LuaHook).GetMethod("Capture"));
            Engine.lua.RegisterFunction("AddMousePointer", null, typeof(LuaHook).GetMethod("AddMousePointer"));
            Engine.lua.RegisterFunction("AnimateMousePointer", null, typeof(LuaHook).GetMethod("AnimateMousePointer"));
            Engine.lua.RegisterFunction("GetMousePos", null, typeof(LuaHook).GetMethod("GetMousePos"));
        }

        #region CORE
        public static void Call(string function)
        {
            LuaInterface.LuaFunction f = Engine.lua.GetFunction(function);
            if (f != null)
                f.Call();
        }

        public static object Lerp(object value1, object value2, float position)
        {
            if (value1 is int)
                return ((int)value1).Lerp((int)value2, position);
            else if (value1 is float)
                return ((float)value1).Lerp((float)value2, position);
            else if (value1 is Vector3Df)
                return ((Vector3Df)value1).Lerp((Vector3Df)value2, position);
            else if (value1 is Color)
                return ((Color)value1).Lerp((Color)value2, position);
            else if (value1 is Colorf)
                return ((Colorf)value1).Lerp((Colorf)value2, position);
            else return null;
        }

        public static int Clamp(int value, int min, int max)
        {
            return value.Clamp(min, max);
        }

        public static Vector2Di Vector2i(int x, int y)
        {
            return new Vector2Di(x, y);
        }

        public static Vector2Df Vector2(float x, float y)
        {
            return new Vector2Df(x, y);
        }

        public static Vector3Df Vector3(float x, float y, float z)
        {
            return new Vector3Df(x, y, z);
        }

        public static Color Color(int r, int g, int b, int a)
        {
            return new Color(r, g, b, a);
        }

        public static Recti Rect(int x1, int y1, int x2, int y2)
        {
            return new Recti(x1, y1, x2, y2);
        }

        public static bool PointInside(Recti rect, Vector2Di point)
        {
            return rect.IsPointInside(point);
        }

        public static string[] StringArray(int v)
        {
            return new string[v];
        }

        public static KeyCode KeyCode(string name)
        {
            return (KeyCode)Enum.Parse(typeof(KeyCode), name, true);
        }

        public static MouseEventType MouseEvent(string name)
        {
            return (MouseEventType)Enum.Parse(typeof(MouseEventType), name, true);
        }
        #endregion

        #region ENGINE
        public static string BaseData()
        {
            return Engine.baseData;
        }

        /*public static void LoadPlugin(string name, string filename)
        {
            Engine.plugins.Add(name, Assembly.LoadFile(System.IO.Path.GetFullPath(filename)));
            foreach (Type type in Engine.plugins[name].GetModules()[0].GetTypes())
                if (type.Name == "Main")
                    type.GetMethod("OnLoad").Invoke(null, null);
        }*/

        public static void ClearTextures()
        {
            Engine.device.VideoDriver.RemoveAllTextures();
        }

        public static object GetGlobalVariable(string name)
        {
            return Engine.globalVariables[name];
        }

        public static void SetGlobalVariable(string name, object value)
        {
            if (Engine.globalVariables.ContainsKey(name))
                Engine.globalVariables.Remove(name);
            Engine.globalVariables.Add(name, value);
        }

        public static void SetTitle(string title)
        {
            Engine.device.SetWindowCaption(title);
        }

        public static string[] ReadFile(string filename)
        {
            return filename.GetFileLines();
        }

        public static void WriteFile(string filename, string[] content)
        {
            System.IO.File.WriteAllLines(filename, content);
        }

        public static void KeyboardReset()
        {
            Keyboard.Reset();
        }

        public static bool KeyboardDown(KeyCode key)
        {
            return Keyboard.IsKeyDown(key);
        }

        public static void LoadField(string name)
        {
            Engine.LoadScene(new Scene(name));
        }

        public static void LoadFieldPOS(string name, Vector3Df position)
        {
            Engine.LoadScene(new Scene(name, position));
        }

        public static void LoadScene(string name)
        {
            Engine.LoadScene((IScene)Type.GetType(name).GetConstructor(new Type[0]).Invoke(null));
        }

        public static void EndGame()
        {
            Engine.device.Close();
        }

        public static uint GetCurrentTime()
        {
            return Engine.currentTime;
        }

        public static void AddTimeTrigger(uint timecode, string function)
        {
            Engine.timeline.operations.Add(new TimedOperation(timecode,
                new EventHandler<TimedEventArgs>((object s, TimedEventArgs args) =>
                {Engine.lua.GetFunction(function).Call();})));
        }

        public static void AddTimeTriggerLerp(uint begin, uint end, string function)
        {
            Engine.timeline.operations.Add(new LerpOperation(begin, end,
                new EventHandler<LerpEventArgs>((object s, LerpEventArgs args) =>
                { Engine.lua.GetFunction(function).Call(args.begin, args.end, args.current); })));
        }

        public static void PlaySound(string name, string file, bool playLooped, float speed, float pan, float volume)
        {
            if (!Engine.sounds.ContainsKey(name))
            {
                ISound sound = Engine.soundEngine.Play2D(Engine.baseData + "sounds\\" + file, playLooped,true);
                sound.PlaybackSpeed = speed;
                sound.Volume = volume;
                sound.Pan = pan;
                Engine.sounds.Add(name, sound);
                sound.Paused = false;
            }
        }

        public static void FadeInSound(string name, uint time)
        {
            Engine.timeline.operations.Add(new LerpOperation(Engine.currentTime, Engine.currentTime + time,
                new EventHandler<LerpEventArgs>((object s, LerpEventArgs args) =>
                {
                    if (Engine.sounds.ContainsKey(name))
                        Engine.sounds[name].Volume = Utility.Lerp(0f, 1f, (float)(args.current - args.begin) / (float)(args.end - args.begin));
                })));
        }

        public static void FadeOutSound(string name, uint time)
        {
            Engine.timeline.operations.Add(new LerpOperation(Engine.currentTime, Engine.currentTime + time,
                new EventHandler<LerpEventArgs>((object s, LerpEventArgs args) =>
                {
                    if (Engine.sounds.ContainsKey(name))
                        Engine.sounds[name].Volume = Utility.Lerp(1f, 0f, (float)(args.current - args.begin) / (float)(args.end - args.begin));
                })));
        }

        public static void StopSound(string name)
        {
            if (Engine.sounds.ContainsKey(name))
            {
                Engine.sounds[name].Stop();
                Engine.sounds[name].Dispose();
                Engine.sounds.Remove(name);
            }
        }

        public static void StopAllSound()
        {
            foreach (ISound sound in Engine.sounds.Values)
            {
                sound.Stop();
                sound.Dispose();
            }
            Engine.sounds.Clear();
        }

        public static ISound GetSound(string name)
        {
            if (Engine.sounds.ContainsKey(name))
                return Engine.sounds[name];
            else
                return null;
        }

        public static void MainVolume(float value)
        {
            Engine.soundEngine.SoundVolume = value;
        }
        #endregion

        #region FIELD
        public static void AddCustomPlugin(string className, string name, object parameter)
        {
            ((Scene)Engine.currentScene).plugins.Add(name, (ICustomPlugin)Type.GetType(className)
                .GetConstructor(new Type[1] { typeof(object) }).Invoke(new object[] { parameter }));
            ((Scene)Engine.currentScene).plugins[name].Load();
        }

        public static ICustomPlugin GetCustomPlugin(string name)
        {
            return ((Scene)Engine.currentScene).plugins[name];
        }

        public static void RemoveCustomPlugin(string name)
        {
            ((Scene)Engine.currentScene).plugins[name].Unload();
            ((Scene)Engine.currentScene).plugins.Remove(name);
        }

        public static void AddObject(string name, string spriteName, float width, float height, Vector3Df position)
        {
            ((Scene)Engine.currentScene).spritesKeys.Add(name);
            ((Scene)Engine.currentScene).objects.Add(name,
                new AnimatedSprite(spriteName, new Dimension2Df(width, height), position, (((Scene)Engine.currentScene).spriteRotation), false));
        }

        public static void AddObjectCameraFacing(string name, string spriteName, float width, float height, Vector3Df position)
        {
            ((Scene)Engine.currentScene).spritesKeys.Add(name);
            ((Scene)Engine.currentScene).objects.Add(name,
                new AnimatedSprite(spriteName, new Dimension2Df(width, height), position, (((Scene)Engine.currentScene).spriteRotation), true));
        }

        public static AnimatedSprite GetObject(string name)
        {
            return ((Scene)Engine.currentScene).objects[name];
        }

        public static void AnimateObject(string name, string anim)
        {
            ((Scene)Engine.currentScene).objects[name].SetAnimation(anim);
        }

        public static void RemoveObject(string name)
        {
            ((Scene)Engine.currentScene).objects[name].Remove();
            ((Scene)Engine.currentScene).objects.Remove(name);
            ((Scene)Engine.currentScene).spritesKeys.Remove(name);
        }

        public static void ObjectTransparent(string name, bool filtering)
        {
            ((Scene)Engine.currentScene).objects[name].sceneNode.SetMaterialFlag(MaterialFlag.BilinearFilter, filtering);
            ((Scene)Engine.currentScene).objects[name].sceneNode.SetMaterialType(MaterialType.TransparentAlphaChannel);
            ((Scene)Engine.currentScene).objects[name].sceneNode.SetMaterialFlag(MaterialFlag.ZWrite, true);
            Engine.device.SceneManager.Attributes.SetValue("Allow_ZWrite_On_Transparent", true);
        }

        public static void AddPlayer(string name, float width, float height, Vector3Df position, float speed, Vector3Df offset, float orientation)
        {
            if (((Scene)Engine.currentScene).player != null)
                RemovePlayer();
            ((Scene)Engine.currentScene).player = new FieldPlayer(new AnimatedSprite(name, new Dimension2Df(width, height), position,
                ((Scene)Engine.currentScene).spriteRotation, false), speed, offset, orientation);
        }

        public static void AddPlayerCameraFacing(string name, float width, float height, Vector3Df position, float speed, Vector3Df offset, float orientation)
        {
            if (((Scene)Engine.currentScene).player != null)
                RemovePlayer();
            ((Scene)Engine.currentScene).player = new FieldPlayer(new AnimatedSprite(name, new Dimension2Df(width, height), position,
                ((Scene)Engine.currentScene).spriteRotation, true), speed, offset, orientation);
        }

        public static FieldPlayer GetPlayer()
        {
            return ((Scene)Engine.currentScene).player;
        }

        public static void RemovePlayer()
        {
            ((Scene)Engine.currentScene).player.Remove();
            ((Scene)Engine.currentScene).player = null;
        }

        public static void SetPlayer(string spriteName, float width, float height, Vector3Df position, float speed, Vector3Df offset, float orientation)
        {
            if (((Scene)Engine.currentScene).player != null)
                ((Scene)Engine.currentScene).player.Remove();
            ((Scene)Engine.currentScene).player = new FieldPlayer(new AnimatedSprite(spriteName,
                new Dimension2Df(width, height), position, ((Scene)Engine.currentScene).spriteRotation, false), speed, offset, orientation);
        }

        public static void FadeIn(uint time)
        {
            ((Scene)Engine.currentScene).faderColor = IrrlichtLime.Video.Color.OpaqueBlack;
            Engine.timeline.operations.Add(new LerpOperation(Engine.currentTime, Engine.currentTime + time, new EventHandler<LerpEventArgs>(
                (object s, LerpEventArgs e) =>
                {
                    ((Scene)Engine.currentScene).faderColor = Utility.Lerp(IrrlichtLime.Video.Color.OpaqueBlack, new IrrlichtLime.Video.Color(0, 0, 0, 0),
                        (float)(e.current - e.begin) / (float)(e.end - e.begin));
                })));
        }

        public static void FadeOut(uint time)
        {
            ((Scene)Engine.currentScene).faderColor = new IrrlichtLime.Video.Color(0, 0, 0, 0);
            Engine.timeline.operations.Add(new LerpOperation(Engine.currentTime, Engine.currentTime + time, new EventHandler<LerpEventArgs>(
                (object s, LerpEventArgs e) =>
                {
                    ((Scene)Engine.currentScene).faderColor = Utility.Lerp(new IrrlichtLime.Video.Color(0, 0, 0, 0), IrrlichtLime.Video.Color.OpaqueBlack,
                        (float)(e.current - e.begin) / (float)(e.end - e.begin));
                })));
        }

        public static void SpriteRotation(float value)
        {
            ((Scene)Engine.currentScene).spriteRotation = value;
            foreach (AnimatedSprite sprite in ((Scene)Engine.currentScene).objects.Values)
                sprite.sceneNode.Rotation = new Vector3Df(0, value, 0);
            foreach (FieldNPC sprite in ((Scene)Engine.currentScene).npcs.Values)
                sprite.sprite.sceneNode.Rotation = new Vector3Df(0, value, 0);
            if (((Scene)Engine.currentScene).player != null)
                ((Scene)Engine.currentScene).player.sprite.sceneNode.Rotation = new Vector3Df(0, value, 0);
        }

        public static void BasePlane(float scaleX, float scaleY, float rotX, float rotY, float rotZ, bool filtering)
        {
            ((Scene)Engine.currentScene).basePlane.Rotation = new Vector3Df(rotX, rotY, rotZ);
            ((Scene)Engine.currentScene).basePlane.Scale = new Vector3Df(scaleX, 0, scaleY);
            ((Scene)Engine.currentScene).forePlane.Rotation = new Vector3Df(rotX, rotY, rotZ);
            ((Scene)Engine.currentScene).forePlane.Scale = new Vector3Df(scaleX, 0, scaleY);
            ((Scene)Engine.currentScene).basePlane.SetMaterialFlag(IrrlichtLime.Video.MaterialFlag.BilinearFilter, filtering);
            ((Scene)Engine.currentScene).forePlane.SetMaterialFlag(IrrlichtLime.Video.MaterialFlag.BilinearFilter, filtering);
        }

        public static void CamLimits(float x1, float y1, float x2, float y2)
        {
            ((Scene)Engine.currentScene).camLimits = new Rectf(x1, y1, x2, y2);
        }

        public static void CamPos(float x, float y, float z, float lx, float ly, float lz)
        {
            Engine.camera.Position = new Vector3Df(x, y, z);
            Engine.camera.Target = new Vector3Df(lx, ly, lz);
            ((Scene)Engine.currentScene).originalCamPos = Engine.camera.Position;
            ((Scene)Engine.currentScene).originalCamTarget = Engine.camera.Target;
        }

        public static void CamIso(bool iso, float fov, float angle1, float angle2)
        {
            if (iso)
                Engine.camera.SetProjectionMatrix(Matrix.Identity.BuildProjectionMatrixOrthoLH(angle1, angle2, 0.01f, 1000000), true);
            else
                Engine.camera.SetProjectionMatrix(Matrix.Identity.BuildProjectionMatrixPerspectiveFovLH(
                    fov, (float)Engine.device.VideoDriver.ViewPort.Width / (float)Engine.device.VideoDriver.ViewPort.Height, 0.01f, 100000f), false);
        }

        public static void AnimatePlayer(string animName)
        {
            ((Scene)Engine.currentScene).player.Animate(animName);
        }

        public static void PlayerControl(bool control)
        {
            ((Scene)Engine.currentScene).player.playerControl = control;
        }

        public static void AddNPC(string name, string spriteName, float width, float height, Vector3Df position, string updateFunction, string actionButtonFunction)
        {
            ((Scene)Engine.currentScene).npcs.Add(name, new FieldNPC(new AnimatedSprite(spriteName,
                new Dimension2Df(width, height), position, ((Scene)Engine.currentScene).spriteRotation, false), updateFunction, actionButtonFunction));
        }

        public static void AddNPCCameraFacing(string name, string spriteName, float width, float height, Vector3Df position, string updateFunction, string actionButtonFunction)
        {
            ((Scene)Engine.currentScene).npcs.Add(name, new FieldNPC(new AnimatedSprite(spriteName,
                new Dimension2Df(width, height), position, ((Scene)Engine.currentScene).spriteRotation, true), updateFunction, actionButtonFunction));
        }

        public static FieldNPC GetNPC(string name)
        {
            return ((Scene)Engine.currentScene).npcs[name];
        }

        public static void RemoveNPC(string name)
        {
            ((Scene)Engine.currentScene).npcs.Remove(name);
        }

        public static void AnimateNPC(string name, string animName)
        {
            ((Scene)Engine.currentScene).npcs[name].Animate(animName);
        }

        public static void MovePlayer(Vector3Df position)
        {
            ((Scene)Engine.currentScene).player.sprite.sceneNode.Position = position;
        }

        public static void MoveNPC(string name, Vector3Df position)
        {
            ((Scene)Engine.currentScene).npcs[name].sprite.sceneNode.Position = position;
        }

        public static void TimedAnimatePlayer(string animName, uint timecode)
        {
            Engine.timeline.operations.Add(new TimedOperation(timecode,
                new EventHandler<TimedEventArgs>((object s, TimedEventArgs args) =>
                { ((Scene)Engine.currentScene).player.Animate(animName); })));
        }

        public static void TimedAnimateNPC(string name, string animName, uint timecode)
        {
            Engine.timeline.operations.Add(new TimedOperation(timecode,
                new EventHandler<TimedEventArgs>((object s, TimedEventArgs args) =>
                { ((Scene)Engine.currentScene).npcs[name].Animate(animName); })));
        }

        public static void LerpMovePlayer(Vector3Df vbegin, Vector3Df vend, uint begin, uint end)
        {
            Engine.timeline.operations.Add(new LerpOperation(begin, end,
                new EventHandler<LerpEventArgs>((object s, LerpEventArgs args) =>
                    { 
                        ((Scene)Engine.currentScene).player.sprite.sceneNode.Position =
                            Utility.Lerp(vbegin, vend, (float)(args.current - args.begin) / (float)(args.end - args.begin));
                    })));
        }

        public static void LerpMoveNPC(string name, Vector3Df vbegin, Vector3Df vend, uint begin, uint end)
        {
            Engine.timeline.operations.Add(new LerpOperation(begin, end,
                new EventHandler<LerpEventArgs>((object s, LerpEventArgs args) =>
                    {
                        ((Scene)Engine.currentScene).npcs[name].sprite.sceneNode.Position =
                            Utility.Lerp(vbegin, vend, (float)(args.current - args.begin) / (float)(args.end - args.begin));
                    })));
        }

        public static void AddTrigger(string function, Vector3Df position, float size, int type)
        {
            ((Scene)Engine.currentScene).triggers.Add(new PositionTrigger(position, size, function, type));
        }

        public static void RemoveTrigger(string function, Vector3Df position, float size, int type)
        {
            ((Scene)Engine.currentScene).triggers.Remove(new PositionTrigger(position, size, function, type));
        }

        public static void AddMenu(string name, string function, string font, float size, Color color1, Color color2, int x, int y,
            int xSize, int ySize, int spacing, string[] options)
        {
            Menu menu = new Menu(new System.Drawing.Font(font, size),
                new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb((int)color1.ARGB)),
                new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb((int)color2.ARGB)),
                new Vector2Di(x, y), xSize, ySize, spacing, options);
            menu.Load();
            menu.OnSelect += new EventHandler((object s, EventArgs args) => { Engine.lua.GetFunction(function).Call(); });
            ((Scene)Engine.currentScene).menus.Add(name, menu);
        }

        public static Menu GetMenu(string name)
        {
            return ((Scene)Engine.currentScene).menus[name];
        }

        public static void RemoveMenu(string name)
        {
            ((Scene)Engine.currentScene).menus[name].Delete();
            ((Scene)Engine.currentScene).menus.Remove(name);
        }

        public static void AddText(string name, string val, string font, float size, Color color, int x, int y, int xSize, int ySize)
        {
            UIText text = new UIText(val, new System.Drawing.Font(font, size), System.Drawing.Color.FromArgb((int)color.ARGB), new Vector2Di(x, y), new Dimension2Di(xSize, ySize));
            ((Scene)Engine.currentScene).texts.Add(name, text);
        }

        public static UIText GetText(string name)
        {
            return ((Scene)Engine.currentScene).texts[name];
        }

        public static void RemoveText(string name)
        {
            ((Scene)Engine.currentScene).texts[name].Delete();
            ((Scene)Engine.currentScene).texts.Remove(name);
        }

        public static void AddRect(string name, int x, int y, int xSize, int ySize)
        {
            ((Scene)Engine.currentScene).rects.Add(name, new Recti(x, y, x + xSize, y + ySize));
        }

        public static void RemoveRect(string name)
        {
            ((Scene)Engine.currentScene).rects.Remove(name);
        }

        public static void AddSprite(string name, string sprite, int destX, int destY, int width, int height)
        {
            ((Scene)Engine.currentScene).sprites.Add(name, new UISprite(sprite, new Recti(destX, destY, destX + width, destY + height)));
        }

        public static UISprite GetSprite(string name)
        {
            return ((Scene)Engine.currentScene).sprites[name];
        }

        public static void RemoveSprite(string name)
        {
            ((Scene)Engine.currentScene).sprites[name].Delete();
            ((Scene)Engine.currentScene).sprites.Remove(name);
        }

        public static void AnimateSprite(string name, string animName)
        {
            ((Scene)Engine.currentScene).sprites[name].sprite.SetAnimation(animName);
        }

        public static void SetBackground(string name)
        {
            ((Scene)Engine.currentScene).back = Engine.device.VideoDriver.GetTexture(Engine.baseData + "ui/" + name + ".jpg");
        }

        public static void SetForeground(string name)
        {
            ((Scene)Engine.currentScene).foreground = Engine.device.VideoDriver.GetTexture(Engine.baseData + "ui/" + name + ".jpg");
        }

        public static Texture Capture()
        {
            return Engine.device.VideoDriver.AddTexture("capture", Engine.device.VideoDriver.CreateScreenShot());
        }

        public static void AddMousePointer(string name, int width, int height)
        {
            ((Scene)Engine.currentScene).pointer = new MousePointer(name, width, height);
        }

        public static void AnimateMousePointer(string name)
        {
            ((Scene)Engine.currentScene).pointer.sprite.SetAnimation(name);
        }

        public static Vector2Di GetMousePos()
        {
            return Engine.device.CursorControl.Position;
        }
        #endregion
    }
}
